﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using CodeSpirit.Core.Attributes;
using CodeSpirit.Core.Authorization;

namespace CodeSpirit.Authorization
{
    public class RolePermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
    {
        private readonly ILogger<RolePermissionAuthorizationHandler> logger;

        public RolePermissionAuthorizationHandler(ILogger<RolePermissionAuthorizationHandler> logger)
        {
            this.logger = logger;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            // 确保 Resource 是 HttpContext
            if (context.Resource is not HttpContext httpContext)
            {
                return Task.CompletedTask;
            }

            Endpoint endpoint = httpContext.GetEndpoint();
            if (endpoint == null)
            {
                return Task.CompletedTask;
            }

            // 允许匿名访问的终结点直接授权
            if (endpoint.Metadata.GetMetadata<AllowAnonymousAttribute>() != null)
            {
                context.Succeed(requirement);
                return Task.CompletedTask;
            }

            if (context.User?.Claims != null)
            {
                var currentUser = httpContext.RequestServices.GetService<ICurrentUser>();
                // 提前转换为 HashSet 提高查找效率
                HashSet<string> roles = currentUser?.Roles?.ToHashSet() ?? [];

                // 管理员直接通过
                if (roles.Contains("Admin"))
                {
                    context.Succeed(requirement);
                    return Task.CompletedTask;
                }

                // 检查权限
                PermissionAttribute permissionAttribute = endpoint.Metadata.GetMetadata<PermissionAttribute>();
                string permissionName = null;
                if (permissionAttribute?.Name != null)
                {
                    permissionName = permissionAttribute.Name;
                }
                else
                {
                    // 如果没有显式指定权限名称，则根据路由生成默认的权限代码
                    string controllerName = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>()?.ControllerName;
                    string actionName = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>()?.ActionName;

                    if (!string.IsNullOrEmpty(controllerName) && !string.IsNullOrEmpty(actionName))
                    {
                        string modulePrefix = endpoint.Metadata.GetMetadata<ModuleAttribute>()?.Name ?? "default";
                        
                        // 判断是否为HttpOptions请求
                        if (httpContext.Request.Method == HttpMethods.Options)
                        {
                            // HttpOptions请求的权限名称格式：{module}_{controller}
                            permissionName = $"{modulePrefix}_{controllerName.ToCamelCase()}";
                        }
                        else
                        {
                            // 生成格式：{module}_{controller}_{action}，与 PermissionService 保持一致
                            permissionName = $"{modulePrefix}_{controllerName.ToCamelCase()}_{actionName.ToCamelCase()}";
                        }
                    }
                    else
                    {
                        logger.LogWarning("Unable to determine permission name for endpoint {EndpointDisplayName}", endpoint.DisplayName);
                        return Task.CompletedTask;
                    }
                }
                // 从服务容器中获取IHasPermissionService实例，使用Scoped生命周期
                var hasPermissionService = httpContext.RequestServices.GetRequiredService<IHasPermissionService>();
                if (hasPermissionService.HasPermission(permissionName))
                {
                    logger.LogDebug("User {UserId} has permission {PermissionCode}", currentUser.Id, permissionName);
                    context.Succeed(requirement);
                }
                else
                {
                    logger.LogWarning("User {UserId} does not have permission {PermissionCode}", currentUser.Id, permissionName);
                }
            }

            return Task.CompletedTask;
        }
    }
}
